package xyz.app.accessors;

import jakarta.persistence.metamodel.SingularAttribute;
import lombok.NonNull;
import xyz.app.AbstractDomain;
import xyz.app.AbstractDomain_;
import xyz.app.logic.PersistenceLogic;
import xyz.app.queries.CriteriaWrapperQuery;

import java.util.*;

public interface DbReader<T extends AbstractDomain> extends DbAccessor<T> {

    default boolean isAttributeDefinesEqualsCustom(@NonNull SingularAttribute<? super T, ?> attribute) {

        var attributeName = attribute.getName();
        info("Checking if attribute defines equals custom: [{}], [{}]",
                attribute.getDeclaringType().getJavaType().getSimpleName(), attributeName);

        var attributeDefinesEqualsCustom = switch (attributeName) {
            case AbstractDomain_.ID, AbstractDomain_.BUSINESS_KEY -> false;
            default -> true;
        };
        info("Attribute defines equals custom: [{}]", attributeDefinesEqualsCustom);

        return attributeDefinesEqualsCustom;
    }

    default <V> @NonNull Collection<T> find(@NonNull String name, V value) {
        return new CriteriaWrapperQuery.OneClass<>(this)
                .whereEqualsOrNull(name, value)
                .getResultList();
    }

    default @NonNull Collection<T> find() {
        return new CriteriaWrapperQuery.OneClass<>(this).getResultList();
    }

    default Optional<T> findEqualsCustom(@NonNull T t) {

        info("Attempt to find equals custom entity [{}]", t.string());

        var predicateMap = new HashMap<String, Object>();

        for (var attribute : extractAttributes())
            if (isAttributeDefinesEqualsCustom(attribute))
                predicateMap.put(attribute.getName(), getMember(t, attribute));

        return new CriteriaWrapperQuery.OneClass<>(this)
                .whereEqualsOrNull(predicateMap)
                .getSingleResult();
    }

    default PersistenceLogic<T> buildPersistenceLogic(@NonNull T t) {
        return PersistenceLogic.of(this).process(t);
    }
}